常用数据结构栈的应用—-表达式求值
栈
栈是常用的数据结构,栈又称堆栈,是一种受限的线性表。其限制是允许在表中的一端进行插入和删除元素。栈中的元素符合后进先出(FILO)的性质。允许插入和删除元素的一端被称为栈顶,另一端被称为栈底。
栈有两种关键的操作,分别为出栈和压栈。
栈有两种关键的操作,分别为出栈和压栈。
- 出栈(pop):它是把栈顶的元素E删除,使E的下一个元素称为新的栈顶,并返回元素E
- 压栈(push):它是将元素E插入栈顶,使得新插入的元素E称为新的栈顶。
栈的常见的应用主要有:编译器中语法分析的符号匹配、表达式求值、程序的函数调用等。
例如:操作系统中的进程的上下文切换,里面被切换下CPU的进程的现场信息例如寄存器等信息,被保存在堆栈中,等到CPU轮转到该进程时,使用堆栈恢复现场。
表达式求值
表达式求值是栈的一个重要的应用。例如计算器中的加减乘除表达式的计算,都会使用栈来进行求值。
表达式的表示方法主要有中缀表示法和后缀表示法。
中缀表示法:操作符号处于两个操作数的中间例如3+4,中缀表达式是符合人们思维的算术表达式方法,中缀表达式通常包含圆括号和方括号。中缀表达式不容易被计算机所理解,因此不太方便使用其进行表达式求值。
中缀表示的例子 1 + 3 * (4 + 5)
后缀表达式:不包含括号,运算符号放在两个运算对象的后面,所有的计算按运算符号出现的顺序,严格的从左向右进行运算(不再需要考虑运算符号的优先规则)。
后缀表达式的例子21+3 对应中缀表达式为(2+1)3
后缀表达式求值
使用后缀表达式进行求值的时候,不需要考虑括号和运算符号的优先规则,只需要从左到右进行计算求值即可。
后缀表达式的求值过程为:
1. 读入操作数,压入栈中直到读取到操作符
2. 如果读取到为操作符,则将栈顶的前两元素出栈,使用该操作符进行运算,得到计算结果
3. 将计算结果压入栈中
4. 重复1、2、3直到表达式末尾
最后栈中只有一个元素,变为最后的计算结果。将其出栈即可。
例如:
中缀表达式(2+1)*3
对应的后缀表达式为21+3*
- 初始化栈S
- 读取2和1压入S,此时S为
1,2
- 读取到操作符+,出栈栈顶两元素得到
1,2
,此时栈为空 - 使用操作符计算两操作数,得到
3(1 + 2 = 3)
,将3
压入栈S,此时栈S为3
- 读入
3
,压入栈S,此时栈为3,3
- 读取到操作符*,出栈栈顶两元素得到
3,3
此时栈S为空 - 使用操作符*,对两元素进行运算得到
9
,将9
压入栈S - 读取到表达式尾部
出栈栈顶元素得到9
即为计算结果
计算机通常使用后缀表达式进行表达式求值,但是人们通常输入计算的表达式是中缀表达式,因此在进行表达式求值的时候,应该先将中缀表达式转为后缀表达式,然后使用后缀表达式求出表达式值。后缀表达式求值的过程很简单,已经上面分析过了。现在关键的一步就是中缀表达式转为后缀表达式。
中缀表达式转后缀表达式
中缀表达式转后缀表达式是表达式求值关键的一步,其过程如下:
输入中缀表达式IEXP,
输出后缀表达式SEXP
依次读入中缀表达式IEXP,初始化一个栈S用来存放操作符OP。
1. 如果读取的是操作数,直接输出到SEXP。如果为操作符OP,进入step2,如果为空,证明读取到IEXP尾部,则进入step5
2. 判断OP,若为`(`,无任何输出,直接压栈`(`到S,进入step1;若为`)`,则出栈S的元素输出到SEXP中直到遇见元素`(`,且`(`不输出到SEXP中,然后进入step1;若OP不为`(`和`)`,则执行step3
3. 判断栈S的栈顶元素是否为`(`,若为`(`,则直接将OP压栈到S中;若不为`(`,则将栈S的元素出栈输出到SEXP中,直到栈顶元素的优先级小于OP或者栈空,最后进入step4
4. 将OP压入栈S中,进入step1
5. 将栈所有元素输出到SEXP中
例如
IEXP为(2+1)*3
,
初始化一个空栈S.
- 读取到操作符
(
,直接压入栈S,此时栈S为(、
。 - 读取到操作数
2
,则直接输出到SEXP,此时S仍为(
,SEXP为2
- 读取到操作符号
+
,由于栈S栈顶元素为(
,因此直接将+
,压入栈S中,此时SEXP为2
,栈S为(、+
- 读取到操作数
1
,直接输出,此时SEXP为21
, 栈S为(、+
。 - 读取到操作符
)
,则出栈S的元素直到碰见(
,不输出(
和)
,则SEXP为21+
,栈S为空 - 读取到操作符号
*'
压栈到S,此时SEXP仍为21+
,栈S为*
- 读取到操作数
3
,直接输出到SEXP中,SEXP为21+3
,栈S为*
读取到文件尾,则出栈S知道栈空,SEXP为
21+3*
最后得到后缀表达式
21+3*
可见,中缀转后缀的关键点在于读取到的操作符为括号的case,栈中的
(
保留直到遇见操作符)
,否则是不会出栈的。
代码示例
1 | //int栈 |